package com.RBGame;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Random;
import java.util.StringTokenizer;

import android.content.res.Resources;

public class Graph {
	int size;
	int match0;
	int matchnow;
	public int dotX[];
	public int dotY[];
	public int dotState[];
	public int deg[];
	boolean isEmpty = true;
	public int removelist[];
	public int removeid[];
	public int removecount = 0;
	public Resources resources;
	 
	// 0= removed;
	// 1= normal;
	// 2= the one to start a file
	public Graph() {
	  this.isEmpty = true;
	}
	
	//public ArrayList<PairInt> edgeList = new  ArrayList<PairInt>();
	public int e1[];
	public int e2[];
	public int edgecount;
	public int map[][];
	public static final int eps = Consts.max_touch_selectdistance_square;
  //  private static Random RNG;
    
    public int nowcsize = 0;
    
    
    /*
    public void make_map(int n, int d , int nogoods) {
    	match0 = 10;
      size = n*d;

	  map = new int[size][size];
	  dotX = new int[size];
	  dotY = new int[size];
	  deg = new int [size];
	  removelist = new int [size];
	  removeid = new int [size];
	  dotState = new int [size];
	  
  	  for (int i = 0 ; i < size; i++)
  		  for (int j = 0 ; j < size; j++)
  			    map[i][j] = 0;
  	  for (int i = 0 ; i < n ; i++)
  		  for (int j = i+1; j< n; j++)
  		  {
  		     int a[] = getrandompair(d,nogoods);
  		     for (int k = 0;k < nogoods; k++) {
  		         int p1 = i*d+a[k+k];
  		         int p2 = j*d+a[k+k+1];
  		         map[p1][p2]= map[p2][p1] = 1;
  		     }
  		  }
    }
   
    public int[] getrandompair(int d, int nogoods) {
      int ans [] = new int[nogoods*2];
      int tmp [][] = new int[d][d];
      int k = 0;
      while (k<nogoods) {
         int p1 = RNG.nextInt(d);
         int p2 = RNG.nextInt(d);
         if (tmp[p1][p2]==0) {
        	 tmp[p1][p2] = 1;
        	 ans[k+k] = p1;
        	 ans[k+k+1] = p2;
        	 k+=2;
         }
      }
      return ans;
    }
    public void make_map() {
       make_map(Consts.default_n,Consts.default_d,Consts.default_nogoods);
    }
    
   */
    
	public Graph(int levelA, int levelB, int width, int height, double scale,
			Resources resources2){
		this.resources = resources2;
	  //dotXY.clear(); dotState.clear();
  //    RNG = new Random();
	  try {
		read_map(levelA,levelB);
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	  dotX= new int[size];
	  dotY = new int[size];

	  
	  removelist = new int [size];
	  removeid = new int [size];
	  dotState = new int [size];
	  int min = ( width<height? width:height) * 4/5;
	  
	  for (int i = 0; i<size;i++) {
		//  System.out.println((int)(width*scale)+(int)(width*(1-scale)*0.5));
		  dotX[i] = width/2 + (int) (min*Math.cos(i*6.28/size));
		  dotY[i] = height/2 + (int) (min*Math.sin(i*6.28/size));
		  
		  //dotX[i] = RNG.nextInt((int)(width*scale)+(int)(width*(1-scale)*0.5));
		  //dotY[i] = RNG.nextInt((int)(height*scale)+(int) (height*(1-scale)*0.5));
		  dotState[i] = 1;
	  }
	  /*
	  edgecount = 0;
	  for (int i = 0; i < size; i++)
		    for (int j = i+1; j<size; j++)
		    	if(map[i][j] ==1) {
		    		edgecount ++;
		    		deg[i]++; deg[j] ++;
		    	}
	  e1 = new int[edgecount];
	  e2 = new int[edgecount];
	  edgecount = 0 ;

	  for (int i = 0; i < size; i++)
		    for (int j = i+1; j<size; j++)
		    	if(map[i][j] ==1) {
		    		e1[edgecount]=i;
		    		e2[edgecount++]=j;
		    	}
		    	*/
	  this.isEmpty = false;
	  int time = 0 ;
	  //locate();
	  while (locate(width,height)>Consts.locate_eps*size && time < Consts.locate_max_time)
		    time ++;
	  scaleinto( width*(1-scale)*0.5, width*(1+scale)*0.5,  height*(1-scale)*0.5, height*(1+scale)*0.5);
	  removecount = 0;
	}
	
	private void read_map(int levelA, int levelB) throws IOException {
	   
		   InputStream ifs  = null;
		   switch (levelA){
		   		case 1 :  {ifs = resources.openRawResource(R.raw.top); break ;	}
		   		//case 2 :  {ifs = resources.openRawResource(R.raw.g2); break ;	}
		   }
		   InputStreamReader read = new InputStreamReader (ifs);  
		   BufferedReader in = new BufferedReader(read);  
		   for (int i = 1; i < levelB; i++) in.readLine();
		   String Line = in.readLine();
		   StringTokenizer tL = new StringTokenizer(Line);
		   size = Integer.parseInt(tL.nextToken());
		   match0 = Integer.parseInt(tL.nextToken());
		   matchnow = match0;
		   edgecount = Integer.parseInt(tL.nextToken());
		   e1 = new int[edgecount];
		   e2 = new int[edgecount];
		   map = new int[size][size];
		   deg = new int [size];
		   for (int i = 0 ; i < edgecount; i++){
			   e1[i] = Integer.parseInt(tL.nextToken());
		       e2[i] = Integer.parseInt(tL.nextToken());
		       map[e1[i]][e2[i]]=1;
		       map[e2[i]][e1[i]]=1;
		       deg[e1[i]]++;
		       deg[e2[i]]++;
		       
		   }
   }
	
	public PairInt getNearestDot(int x0, int y0) {
	   int tmp = 1 << 30;
	   int id = -1;
	   for (int i = 0; i < size; i++)
	      if (dotState[i]!=0){
	        int px = dotX[i]; int py = dotY[i];
		    int now = (x0-px)*(x0-px)+(y0-py)*(y0-py);
		    if (now<tmp) {
			   tmp = now; id = i;
		   }
	   }
	   
	   return new PairInt(tmp,id);
	}

	public int getNearestByXY(int x0, int y0) {   
	   int id = -1;
	   int tmp = (int) eps;
	   for (int i = 0; i < size; i++) 
		   if (dotState[i]!=0){
		   int px = dotX[i]; int py = dotY[i];
		   int now = (x0-px)*(x0-px)+(y0-py)*(y0-py);
		   if (now<tmp) {
			   tmp = now; id = i;
		   }
	   }
	   return id;
	}
	public void setXY(int selDot, float x, float y) {
		dotX[selDot] = (int) x;
		dotY[selDot] = (int) y;
		//dotXY.set(selDot, new PairInt((int)x,(int)y));
	}
	public int setStateByXY(int x0, int y0,int st) {
	    PairInt c = getNearestDot(x0,y0);
	    if (c.x<eps) {
	       dotState[c.y] = st;
	       return c.y;   
	    }
	    return -1;
	    
	}
	/*
	public void reverseStateByXY(int x0, int y0) {
		PairInt c = getNearestDot(x0,y0);
		
	    if (c.x<eps) {
	    	if (dotState.get(c.y).intValue()==2) {
	    		dotState.set(c.y, Integer.valueOf(3));
	    		nowcsize++;
	    	} else 
	    if (dotState.get(c.y).intValue()==3) {
    		dotState.set(c.y, Integer.valueOf(2));
	        nowcsize--;
	    }
	    

	    updateStatus();
	    }
		
	}
	*/
	/*
	public PairInt getDot(int selDot) {
		// TODO Auto-generated method stub
		return dotXY.get(selDot);
	}
	public int getX(int selDot) {
		return dotXY.get(selDot).x;
	}
	public int getY(int selDot) {
		return dotXY.get(selDot).y;
	}
	*/
	public double locate(int width,int height) {
		double dx[] = new double [size];
		double dy[] = new double [size];
		for (int i = 0 ; i <size; i++){
			dx[i] = attractivefunc(dotX[i],width);
		    dy[i] = attractivefunc(dotY[i],height);
		}
		for (int i = 0 ; i < size; i++)
			for (int j = i+1; j<size; j++) if (i!=j) 
			{
			   double dist = Math.sqrt(dist2(i,j));
			   double fij = Consts.locate_g*Consts.defalut_graph_ratio/(dist*dist+0.01);
			   if (map[i][j]==1) 
				//   if (dist>Consts.locate_length)
					   fij -= Consts.locate_k*(dist-Consts.locate_length);
			   double fx = fij*(dotX[j]-dotX[i])/dist;
			   double fy = fij*(dotY[j]-dotY[i])/dist/width*height;
			   
			   dx[i]-=fx; dx[j]+=fx;
			   dy[i]-=fy; dy[j]+=fy;
			}
	    double ans  = 0 ;
	    for (int i = 0 ; i < size; i++) {
	    	if (dotX[i]<=Consts.locate_to_left) dotX[i] = Consts.locate_to_left;
	    	if (dotY[i]<=Consts.locate_to_top) dotY[i] = Consts.locate_to_top;
	    	if (dotX[i]>=width - Consts.locate_to_left) dotX[i] =width -  Consts.locate_to_left;
	    	if (dotY[i]>=height - Consts.locate_to_top) dotY[i] =height - Consts.locate_to_top;
	    	
	    }
	        
	    for (int i = 0 ; i < size; i++){
	    	   dotX[i] = dotX[i] + (int) (dx[i] * Consts.locate_scale );
	    	   dotY[i] = dotY[i] + (int) (dy[i] * Consts.locate_scale);
	           ans += dx[i]*dx[i]+dy[i]*dy[i];
	    }
	    
		return ans;
  	}
	private double attractivefunc(int x, int width) {
		double k  = x*1.0/width - 0.5;
		k = k*k*k*k*Math.tan(k)*0.1;
		return -k;
		
	
	}
	
	public void scaleinto(double d,double e, double f, double g) {
		int minx = 1000000;
		int miny =1000000;
		int maxx = -1000000; int maxy =-1000000;
		for (int i = 0 ; i < size; i++) {
			if (dotX[i] < minx )
				minx = dotX[i];
			if (dotX[i] > maxx )
				maxx = dotX[i];
			
			if (dotY[i] < miny )
				miny = dotY[i];
			if (dotY[i] > maxy )
				maxy = dotY[i];

		}
		for (int i = 0 ; i < size; i++)
		{
				dotX[i] =	(int) (  d + (dotX[i] - minx)*(e-d)/(maxx-minx));
				dotY[i] = 	 (int) ( f + (dotY[i] - miny)*(g-f)/(maxy-miny));
		}			
	
	}
	
	public double dist2(int a, int b) {
		return (dotX[a]-dotX[b])*(dotX[a]-dotX[b])+(dotY[a]-dotY[b])*(dotY[a]-dotY[b]);
	
	}
	public void removeDot(int what) {
		matchnow--;
		for (int i = 0 ; i < size; i++)  
			
		    if (map[i][what]==1 && dotState[i] ==1){
		    	deg[i]--;
		    if (i!=what && deg[i]==0 ) {
				dotState[i] = 0;
				removelist[removecount] = i;
				removeid[removecount] = what;
				removecount++;
			}
		}
		dotState[what] = 0 ;
		removelist[removecount] = removeid[removecount] = what;
		removecount++;
	}
	public void undo() {
		matchnow++;
		int now = removecount;
		while (removeid[now-1] == removeid[removecount-1]) {
		   dotState[removelist[now-1]] = 1;
		   now--;
		   if (now ==0 ) break;
		}
		removecount = now;
		deg = new int[size];
		for (int i = 0 ; i < size; i++)
			for (int j = 0; j < size; j++)
				if (map[i][j]==1 && dotState[j]!=0) deg[i]++;
	}

	public int allremovedint() {
		int id = 0 ;
		for (int i = 0; i < size; i ++  )
			if (dotState[i] ==0) id++;
		return id;
	}
	
	public boolean allremovedboolean() {
	
		for (int i = 0; i < size; i ++  )
			if (dotState[i] ==1) return false;
		return true;
	}
	
}
